package ru.rchervot.sanasar.client.model;

import java.util.ArrayList;

import com.google.gwt.user.client.rpc.IsSerializable;

public class DefaultResultsPage<T extends SearchResultsItem> implements ResultsPage<T>, IsSerializable {
	
	private static int kPageSizeDefault = 1;
	
	private int pageSize;
	protected int offset;
	private int resultsSize;
	private int queryID;
	
//do not use this constructor, only for serialization
	private DefaultResultsPage() {
		this.items = new ArrayList<T>();
		this.pageSize = kPageSizeDefault;
	}
	
	private DefaultResultsPage(int offset, int pageSize, int resultsSize, int queryID) {
		this();
		
		this.pageSize = pageSize;
		this.offset = offset;
		this.resultsSize = resultsSize;
		this.queryID = queryID;
		
		verifyOffsetBoundaries();
	}
	
	private void verifyOffsetBoundaries() {
		if (offset < 0) offset = 0;
		
		if (offset >= resultsSize) {
			offset = resultsSize - 1;
		}
	}
	
	public static <T extends SearchResultsItem> ResultsPage<T> buildEmptyPage() {
		return new DefaultResultsPage<T>();
	}
	
	public static <T extends SearchResultsItem> ResultsPage<T> build(
			int offset, int pageSize, int resultsSize, int queryID) {
		return new DefaultResultsPage<T>(offset, pageSize, resultsSize, queryID);
	}
	
	@Override
	public int getQueryID() {
		return queryID;
	}

	@Override
	public boolean isEmpty() {
		return resultsSize == 0;
	}
	
	@Override
	public boolean isCurrentOffsetLast() {
		return resultsSize == 0 ? true : offset == (resultsSize - 1);
	}

	@Override
	public boolean isCurrentOffsetFirst() {
		return offset == 0;
	}
	
	@Override
	public int getPageCurrentOffset() {
		return (offset / pageSize) * pageSize;
	}

	@Override
	public int getPageFirstOffset() {
		return 0;
	}
	
	@Override
	public int getPagePrevOffset() {
		int t = getPageCurrentOffset() - pageSize;
		return t > 0 ? t : 0;
	}
	
	@Override
	public int getPageNextOffset() {
		int t = getPageCurrentOffset() + pageSize;
		return t < resultsSize ? t : getPageLastOffset();
	}
	
	@Override
	public int getPageLastOffset() {
		if ((resultsSize % pageSize) == 0) {
			return ((resultsSize / pageSize) - 1) * pageSize;
		} else {
			return (resultsSize / pageSize) * pageSize;			
		}
	}
	
	@Override
	public int getOffset() {
		return offset;
	}
	
	@Override
	public int getOffsetForHumans() {
		return offset + 1;
	}
	
	@Override
	public int getCurrentRow() {
		return offset % pageSize;
	}
	
	@Override
	public void setOffset(int offset) {
		if (offset < getPageCurrentOffset()) offset = getPageCurrentOffset(); //TODO Do we really need these checks?
		if (offset > getPageCurrentOffsetEnd())	offset = getPageCurrentOffsetEnd();
		
		this.offset = offset;
	}
	
	@Override
	public int getPageSize() {
		return pageSize;
	}

	@Override
	public int getResultsSize() {
		return resultsSize;
	}

	@Override
	public boolean hasNext() {
		return (getPageCurrentOffset() + pageSize) < resultsSize ? true : false;
	}

	@Override
	public boolean hasPrevious() {
		return getPageCurrentOffset() != 0 ? true : false;
	}
	
	@Override
	public boolean isContainOffset(int offset) {
		return getPageCurrentOffset() <= offset && offset < getPageNextOffset();
	}
	
	private boolean isRowCurrent(int row) {
		return offset == (getPageCurrentOffset() + row);
	}
	
	private ArrayList<T> items;
	
	@Override
	public ArrayList<T> getItems() {
		return items;
	}
	
	@Override
	public void setItems(ArrayList<T> items) {
		this.items = items;
	}
	
	@Override
	public T getCurrentItem() {
		if (items == null || items.isEmpty()) {
			return null;
		} else {
			System.out.println("getCurrentRow() " + getCurrentRow());
			return items.get(getCurrentRow());
		}
	}
	
	@Override
	public T getItem(int row) {
		if (items == null || items.isEmpty()) {
			return null;
		} else {
			return items.get(row);
		}
	}

	@Override
	public boolean equals(Object o) {
		if (o == null) return false;

		if (! (o instanceof DefaultResultsPage)) return false;

		DefaultResultsPage<?> to = (DefaultResultsPage<?>) o;

		return this.queryID == to.queryID
		&& this.getPageCurrentOffset() == to.getPageCurrentOffset()
		&& this.resultsSize == to.resultsSize
		&& this.pageSize == to.pageSize;
	}

	@Override
	public int hashCode() {
		int result = 17;
		result = 37 * result + queryID + getPageCurrentOffset() + resultsSize + pageSize;
		return result;
	}

	@Override
	public void decreaseOffset() {
		offset--;
	}

	@Override
	public void increaseOffset() {
		offset++;
	}

	@Override
	public boolean isCurrentRowFirst() {
		return offset == getPageCurrentOffset();
	}

	@Override
	public boolean isCurrentRowLast() {
		return offset == getResultsSize() - 1 
		|| offset == getPageNextOffset() - 1;
	}

	@Override
	public int getPageCurrentOffsetEnd() {
		if (resultsSize == 0) {
			return 0;
		} else if (hasNext()) {
			return getPageNextOffset() - 1;
		} else {
			return resultsSize - 1;
		}
	}

	
}
